package cn.feng.process.demo.service.impl;

import cn.feng.process.config.basic.base.ServiceException;
import cn.feng.process.core.ProcessConstant;
import cn.feng.process.core.pojo.DO.Process;
import cn.feng.process.core.pojo.DO.ProcessCondition;
import cn.feng.process.core.pojo.DO.ProcessExecute;
import cn.feng.process.core.pojo.DO.ProcessNode;
import cn.feng.process.demo.mapper.ProcessConditionMapper;
import cn.feng.process.demo.mapper.ProcessExecuteMapper;
import cn.feng.process.demo.mapper.ProcessMapper;
import cn.feng.process.demo.mapper.ProcessNodeMapper;
import cn.feng.process.demo.service.ProcessExecuteService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.sql.SQLException;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 流程执行相关业务实现类
 *
 * @author zzf
 * @date 2020/9/14 15:01
 */
@Service
public class ProcessExecuteServiceImpl extends ServiceImpl<ProcessExecuteMapper, ProcessExecute> implements ProcessExecuteService {

    @Resource
    ProcessMapper processMapper;
    @Resource
    ProcessNodeMapper processNodeMapper;
    @Resource
    ProcessConditionMapper processConditionMapper;


    @Override
    public boolean run(String targetName, long targetId, long userId) {

        Process process = processMapper.selectOne(new LambdaQueryWrapper<Process>()
                .eq(Process::getTargetClassName, targetName)
                .eq(Process::getEnabled, ProcessConstant.DEFAULT_YES)
                .eq(Process::getDeleted, ProcessConstant.DEFAULT_NO)
                .select(Process::getId)
        );
        if (process == null) {
            throw new ServiceException("发起流程失败！未找到有效流程。");
        }
        List<ProcessNode> nodeList = processNodeMapper.selectList(new LambdaQueryWrapper<ProcessNode>()
                .eq(ProcessNode::getProcessId, process.getId())
        );
        List<ProcessCondition> conditionList = processConditionMapper.selectList(new LambdaQueryWrapper<ProcessCondition>()
                .eq(ProcessCondition::getProcessId, process.getId())
        );

        try {
            computeProcessTrendAndAddUser(conditionList, nodeList, ProcessConstant.START_AND_END_NODE_ID, 1, userId);
        } catch (SQLException exception) {
            exception.printStackTrace();
        }

        return true;
    }

    /**
     * 通过递归的方式计算流程走向并增加流程审核人
     * <p>
     * TODO 未完成，这里需要用到流程配置相关的信息，需要等流程配置那边写完才能继续。
     *
     * @param allConditionList 所有条件集合
     * @param nodeList         节点集合
     * @param currentNodeId    当前节点ID
     * @param nodeNum          当前流程节点数
     * @param initiatorUserId  发起人ID
     * @return 此次流程的节点总数
     */
    private int computeProcessTrendAndAddUser(List<ProcessCondition> allConditionList,
                                              List<ProcessNode> nodeList,
                                              int currentNodeId,
                                              int nodeNum,
                                              long initiatorUserId) throws SQLException {
        List<ProcessCondition> currentConditionList = allConditionList.stream()
                .filter(s -> s.getAheadProcessNodeId().equals(currentNodeId))
                .collect(Collectors.toList());

        if (currentConditionList.size() > 1) {
            //表示存在条件


        } else {
            //表示不存在条件
            Integer nextNodeId = currentConditionList.get(0).getHinderProcessNodeId();
            if (ProcessConstant.START_AND_END_NODE_ID.equals(nextNodeId)) {
                return nodeNum;
            }
            for (ProcessNode node : nodeList) {
                if (node.getId().equals(nextNodeId)) {

                    getExamineUserAndAdd(node, initiatorUserId);

                    break;
                }
            }
            allConditionList.removeAll(currentConditionList);
            //computeProcessTrendAndAddUser()

        }
        return nodeNum;
    }

    private void getExamineUserAndAdd(ProcessNode node, long userId) throws SQLException {

    }


}
